<template>
	<div class="tl-ali-oss-upload">
		<!--上传状态显示，以及全部文件的暂停、重试、暂停&失败移除等操作-->
		<div class="flex justify-between align-center tl-ali-oss-upload-toolbar" v-if="fail_num > 0 || pause_num > 0 || uploading_num > 0">
			<div>{{ prompt_text }}</div>
			<div class="flex align-center">
				<div class="action-btn" v-if="uploading_num > 0" @click="handleUploadCancel">全部暂停</div>
				<div class="action-btn" v-else-if="pause_num > 0 || fail_num > 0" @click="allResumeUpload">
					<span v-if="pause_num > 0">全部继续</span>
					<span v-else>失败重试</span>
				</div>
				<div class="action-btn" v-if="uploading_num > 0" @click="handleCancelUpload(false)">全部取消</div>
				<div class="action-btn" v-else-if="fail_num > 0 || pause_num > 0" @click="handleFailRemove()">
					<span v-if="pause_num > 0">暂停移除</span>
					<span v-else>失败移除</span>
				</div>
			</div>
		</div>
		<!--利用element上传组件，实现拖拽上传、接受上传的文件类型、单多文件选项等功能，提高开发效率-->
		<el-upload
			ref="upload"
			:accept="accept"
			:drag="drag"
			action=" "
			:with-credentials="withCredentials"
			:disabled="disabled"
			:limit="limit"
			:show-file-list="false"
			:auto-upload="autoUpload"
			:multiple="multiple && limit !== 1"
			list-type="picture"
			:before-upload="handleBeforeUpload"
			:on-progress="handleFileProgress"
			:on-success="handleFileSuccess"
			:on-error="handleFileError"
			:on-exceed="handleFileExceed"
			:on-change="handleFileChange"
			:http-request="handleHttpRequest"
		>
			<!--实现上传进度显示样式，并兼容自定义样式修改-->
			<slot :files="upload_list" name="upload-list">
				<div class="tl-ali-oss-upload-dragger" v-if="upload_list.length === 0 && !listShowUpload && drag">
					<i class="el-icon-upload"></i>
					<div class="el-upload__text">
						将文件拖到此处，或
						<em>点击上传</em>
					</div>
				</div>
				<template v-else>
					<!--上传进度组件，以及单个文件暂停、重试、暂停&失败移除等功能扩展-->
					<tl-upload-progress
						:list="upload_list"
						is-oss
						@retry-upload="handleRetryUpload"
						:style="[maxHeight > 0 ? { overflowY: 'auto' } : null]"
						:maxHeight="maxHeight > 0 ? maxHeight : 'auto'"
						:show-upload="listShowUpload"
						:action-icon="listActionIcon"
						:show-single-action="listShowSingleAction"
						@click-action="handleClickAction"
						@oss-upload-click="btnTrigger"
					>
						<template v-slot:default-action="{ item }">
							<slot name="default-action" :item="item">
								<el-button
									type="text"
									icon="el-icon-link"
									v-if="!listActionIcon"
									:data-clipboard-text="item.url"
									@click="handleClipboard"
								/>
							</slot>
						</template>
						<template v-slot:action="{ item }">
							<!--TODO action-->
							<slot name="action" :item="item" />
						</template>
						<!--TODO 上传按钮-->
						<slot />
					</tl-upload-progress>
				</template>
			</slot>
			<!--提示说明文字-->
			<template slot="tip">
				<slot name="tip" :note="note">
					<div class="tl-ali-oss__tip el-upload__tip" v-if="note">{{ note }}</div>
				</slot>
			</template>
		</el-upload>
	</div>
</template>

<script>
import ClipboardJS from 'clipboard';
import $ from 'jquery';
import bytes from '@bixiao/utils/lib/bytes';
import { UserOperatingMixins } from '@bixiao/utils-mixins';
import aliYun from './utils/aliYun';
import TlUploadProgress from '@components/tl-ui/upload-progress';
import moment from 'moment';
import { debounce, cloneDeep } from 'lodash';
import MD5 from 'crypto-js/md5';
import SHA256 from 'crypto-js/sha256';
import SparkMD5 from 'spark-md5';

import { Upload, Button } from 'element-ui';

/**
 * 获取上传进度计算
 * @param size
 * @param percentage
 * @returns {number|*}
 */
const getBytesUploaded = function({ size }, percentage) {
	if (percentage >= 100) {
		return size;
	} else {
		return size * (percentage / 100);
	}
};

const hash_MD5 = function(txt, len = 5) {
	const str = MD5(txt).toString();
	const num = Math.floor(Math.random() * 3) + 1;
	return str.substring(0, num) + str.substring(str.length - (len - num), str.length);
};

function getFileHash(file, intact = false) {
	return new Promise(resolve => {
		let blobSlice = File.prototype.slice || File.prototype.mozSlice || File.prototype.webkitSlice,
			chunkSize = 2097152, // 读取2MB的块
			chunks = Math.ceil(file.size / chunkSize), //
			currentChunk = 0,
			spark = new SparkMD5.ArrayBuffer(),
			fileReader = new FileReader();

		fileReader.onload = function(e) {
			console.log('读取区块编号', currentChunk + 1, 'of', chunks);
			console.log('读取区块编号', currentChunk + 1, e.target.result);
			spark.append(e.target.result); // 追加数组缓冲区
			currentChunk++;
			if (currentChunk < chunks) {
				if (intact !== true) currentChunk = chunks - 1;
				loadNext();
			} else {
				console.log('完成加载');
				const hash = spark.end();
				console.info('计算哈希', hash); // 计算哈希
				resolve(hash);
			}
		};

		fileReader.onerror = function() {
			console.warn('oops, something went wrong.');
		};

		function loadNext() {
			let start = currentChunk * chunkSize,
				end = start + chunkSize >= file.size ? file.size : start + chunkSize;
			fileReader.readAsArrayBuffer(blobSlice.call(file, start, end));
		}

		loadNext();
	});
}

export default {
	name: 'tl-ali-oss-upload',
	mixins: [UserOperatingMixins],
	components: {
		[Upload.name]: Upload,
		[Button.name]: Button,
		[TlUploadProgress.name]: TlUploadProgress,
	},
	directives: {},
	data() {
		return {
			images: [],
			progress_images: [],
			error_key: [],
			count: 0,
			auto_upload: true,
			requestQueue: [],
			checkpointMap: new Map(),
			aliYuns: [],
			external_files: [],
		};
	},
	props: {
		drag: {
			type: Boolean,
			default: true,
		},
		// 并发请求数 最大并发 10
		parallel: {
			type: Number,
			default: 4,
		},
		// 分片大小 默认2MB,最大分片10MB
		partSize: {
			type: [Number, String],
			default: '2MB',
		},
		// 所有文件
		fileList: {
			type: Array,
			default: () => [],
		},
		// 文件列表, 例如: [{name: 'food.jpg', url: 'https://xxx.cdn.com/xxx.jpg'}]
		defaultFileList: {
			type: Array,
			default: () => [],
		},
		hideSuccessFile: Boolean,
		// 是否显示
		visible: {
			type: Boolean,
			default: true,
		},
		// 单个文件的最大文件大小 (以字节为单位)
		maxFileSize: {
			type: [Number, String],
			default: '1GB',
		},
		// 最大允许上传个数
		limit: {
			type: Number,
			default: 100,
		},
		// 接受上传的文件类型（thumbnail-mode 模式下此参数无效）
		accept: String,
		// 是否禁用
		disabled: Boolean,
		// 支持发送 cookie 凭证信息
		withCredentials: Boolean,
		// 是否支持多选文件
		multiple: {
			type: Boolean,
			default: true,
		},
		// 上传一级目录（固定）
		directory: {
			type: String,
			default: 'card-enterprise',
		},
		// 上传位置
		uploadPath: {
			type: String,
			default: 'pm/file-library',
		},
		meta: {
			type: Object,
			default() {
				return {
					catalogId: 'bixiao-oss',
					pid: 0,
				};
			},
		},
		// 是否在选取文件后立即进行上传
		autoUpload: {
			type: Boolean,
			default: true,
		},
		trigger: [String, HTMLElement],
		host: String,
		api: {
			type: String,
			default: '/project/attachment/uploadFileCenter',
		},
		note: {
			type: String,
			default: '仅图像和视频，2–3个文件，最大100MB',
		},
		maxHeight: {
			type: Number,
			default: null,
		},
		// 列表属性
		// 是否显示上传按钮
		listShowUpload: {
			type: Boolean,
			default: false,
		},
		// 显示单一动作
		listShowSingleAction: {
			type: Boolean,
			default: true,
		},
		listActionIcon: String,
	},
	computed: {
		upload_pos() {
			return file_name => {
				const { user_id, company_id } = this.userInfo || {};
				const directory = this.directory;
				let path = this.uploadPath.replace(/(^\s*)|(\s*$)/g, '').replace(/(^\/*)|(\/*$)/g, '');
				const env_mode = this.$config.env.get('mode');
				if (env_mode !== 'production') {
					const paths = path.split('/');
					paths[0] = `${paths[0]}-${env_mode}`;
					path = paths.join('/');
				}
				let arr = [directory, path];
				if (company_id) arr.push(company_id);
				if (user_id) arr.push(user_id);
				const time = moment().format('YYYY-MM-DD');
				const file_names = file_name.split('.');
				const suffix = file_names.pop();
				let name = file_names.join('.');
				return {
					path: [...arr, time].join('/'),
					name: name,
					suffix,
					filepath: `${[...arr, time, 'web', name].join('/')}.${suffix}`,
				};
			};
		},
		upload_list() {
			let images = this.images;
			if (this.hideSuccessFile === true) images = images.filter(file => file.status !== 'success' || file.isSubmit !== true);
			return images.concat(this.defaultFileList);
		},
		fail_num() {
			const list = this.images.filter(file => file.status === 'fail');
			return list.length;
		},
		success_num() {
			const list = this.images.filter(file => file.status === 'success');
			return list.length;
		},
		uploading_num() {
			const list = this.images.filter(file => file.status === 'uploading');
			return list.length;
		},
		pause_num() {
			const list = this.images.filter(file => file.status === 'pause');
			return list.length;
		},
		prompt_text() {
			let arr = [];
			if (this.fail_num > 0) arr.push(`失败${this.fail_num}项`);
			if (this.pause_num > 0) arr.push(`暂停${this.pause_num}项`);
			if (this.uploading_num > 0) return '进程中...';
			return arr.join('，');
		},
	},
	watch: {
		['requestQueue.length']() {
			this.handleHttpRequestAll();
		},
		visible(n, o) {
			if (n === true) this.is_cancel_upload = false;
		},
		['upload_list.length']: {
			handler() {
				this.$emit('update:fileList', this.upload_list);
			},
			immediate: true,
		},
	},
	methods: {
		handleClickAction(...args) {
			this.$emit('click-action', ...args);
		},
		// 复制URL
		handleClipboard(e) {
			const clipboard = new ClipboardJS(e.currentTarget);
			clipboard.on('success', e => {
				this.$ele.$message.success('复制成功');
				clipboard.destroy();
			});
			clipboard.on('error', e => {
				this.$ele.$message.error('复制错误，请重新复制！');
				// 释放内存
				clipboard.destroy();
			});
		},
		/**
		 * 初始化
		 */
		async init(callback) {
			const client = await aliYun();
			callback && callback(client);
			this.aliYun = client;
			this.aliYuns.push(client);
			return client;
		},
		// 上传文件改变处理
		setFileList(file, type) {
			if (this.is_cancel_upload === true) return;
			let images = this.images;
			const percentage = file.percentage;
			switch (file.status) {
				case 'ready':
					file.progress = {
						bytesTotal: 0,
						bytesUploaded: 0,
						uploadComplete: false,
						uploadStarted: false,
					};
					break;
				case 'success':
					if (file.response) {
						file.url = file.response && file.response.url;
					}
					file.progress = {
						uploadStarted: true,
						bytesUploaded: file.size,
						bytesTotal: file.size,
						uploadComplete: true,
						percentage,
					};
					break;
				case 'uploading':
					file.progress = {
						uploadStarted: true,
						bytesUploaded: getBytesUploaded(file, percentage),
						bytesTotal: file.size,
						uploadComplete: false,
						percentage,
					};
					break;
				case 'fail':
					break;
			}
			file.id = file.uid;
			if (file.raw && file.raw.filename) {
				file.filename = file.raw.filename;
			}
			const fIndex = images.findIndex(value => value.id === file.id);
			if (fIndex > -1) {
				images.splice(fIndex, 1, file);
			} else {
				images.unshift(file);
			}
		},
		// 监听上传进度
		handleFileProgress(event, file, fileList) {
			console.log(event, file, fileList, '上传完成：handleFileProgress');
			if (file) this.setFileList(file, 'progress');
		},
		// 其它文件监听事件
		handleFileEvents(event, file, fileList) {
			console.log(event, file, fileList, '上传完成：handleFileEvents');
			this.$emit('progress', event, file, fileList);
			this.setFileList(file);
		},
		// 监听上传成功
		handleFileSuccess(response, file, fileList) {
			console.log(response, file, fileList, '上传成功：handleFileSuccess');
			this.$emit('success', response, file, fileList);
		},
		// 监听上传失败
		handleFileError(err, file, fileList) {
			console.log(err, file, fileList, '上传失败：handleFileError');
			this.$emit('error', err, file, fileList);
		},
		// 文件超出个数限制时的钩子
		handleFileExceed(err, file, fileList) {
			console.log(err, file, fileList, '上传失败：handleFileExceed');
			this.$ele.$message.warning(`最大支持上传${this.limit}个文件`);
			this.$emit('exceed', err, file, fileList);
		},
		// 文件状态改变时的钩子，添加文件、上传成功和上传失败时都会被调用
		handleFileChange(file, fileList) {
			console.log(file, fileList, `SHA256:上传文件状态：handleFileChange - ${file.status}`);
			if (file.status !== 'ready') {
				this.setFileList(file);
				this.$emit('change', file, fileList);
			} else {
				this.is_cancel_upload = false;
			}
		},
		// 上传文件之前的钩子，参数为上传的文件，若返回 false 或者返回 Promise 且被 reject，则停止上传。
		handleBeforeUpload(file) {
			const images = this.images;
			return new Promise(async (resolve, reject) => {
				const filepos = this.upload_pos(file.name);
				let bol = false;
				const hash = await getFileHash(file);
				console.log(file, `${file.name}：${hash}`, 'SHA256');
				console.log(images, 'SHA256');
				if (hash) {
					const fIndex = await new Promise(async resolve => {
						let i = 0;
						for (let value of this.images) {
							if (!value.hash) value.hash = await getFileHash(value.raw);
							if (value.hash === hash) return resolve(i);
							i++;
						}
						resolve(-1);
					});
					if (fIndex > -1) {
						this.$ele.$message.warning(`请勿上传相同文件[${file.name}]`);
						return reject(false);
					}
				}

				if (this.limit > 0 && this.images.length > this.limit) {
					this.handleFileExceed(null, file);
					return reject(false);
				}
				if (['string', 'number'].includes(typeof this.maxFileSize)) {
					const maxFileSize = typeof this.maxFileSize === 'string' ? bytes(this.maxFileSize) : this.maxFileSize;
					if (maxFileSize > 0 && file.size > maxFileSize) {
						this.$ele.$message.warning(`当前上传【${file.name}】文件大小不能超过 ${bytes(maxFileSize)}!`);
						return reject(false);
					}
				}

				bol = await this.getOssListDir({ dir: filepos.path }, filepos.filepath);
				if (bol) {
					console.log('重复上传');
					file.filename = `${filepos.name}_${hash_MD5([file.name, file.size, file.type, Date.now()].join('-'))}.${filepos.suffix}`;
					resolve(file);
				} else {
					resolve(file);
				}
			});
		},
		// 获取OSS 对应文件目录下文件
		async getOssListDir({ dir, marker = null }, filepath) {
			const client = this.aliYun;
			const prefix = `${dir}/`;
			if (!this.listDir) this.listDir = new Map();
			let listDir = this.listDir && this.listDir.get(prefix);
			try {
				if (!Array.isArray(listDir)) {
					let result = await client.list({
						prefix: prefix, // 指定只列出符合特定前缀的文件
						marker: marker, // 指定只列出文件名大于marker之后的文件
						delimiter: '/', // 用于获取文件的公共前缀
						maxKeys: 1000, // 用于指定最多返回的文件个数
					});
					listDir = Array.isArray(result.objects) ? result.objects.map(value => value.name) : [];
					this.listDir.set(prefix, listDir);
				}
				if (Array.isArray(listDir)) {
					// 文件
					return listDir.find(value => value === filepath);
				} else {
					return false;
				}
			} catch (e) {
				return true;
			}
		},
		/**
		 * 获取上传参数（进度监听，回调等）
		 * @param onProgress 文件上传进度监听
		 * @param file 文件
		 * @param filepath 文件上传路径
		 * @param isRetrySlice 是否重试上传
		 * @return options {Object} 返回上传的配置参数
		 **/
		getUploadOptions({ onProgress, file }, filepath, isRetrySlice = false) {
			const that = this;
			const host = that.$config.baseUrl.image_host;
			const api_pm = that.$config.env.get('api_pm');
			console.log(api_pm, 'api_pm');
			const progress = (progress, checkpoint) => {
				// 断点记录点。浏览器重启后无法直接继续上传，您需要手动触发上传操作。
				that.checkpointMap.set(file.uid, checkpoint);
				const percent = progress * 100;
				console.log(percent, '上传进度');
				onProgress({ percent, filepath, raw: file }, file);
				const find = this.images.find(value => value.uid === file.uid);
				if (find) find.status = 'uploading';
			};
			let partSize = typeof that.partSize === 'string' ? bytes(that.partSize) : that.partSize;
			const maxPartSize = bytes('10MB');
			if (partSize <= 0 || isNaN(partSize)) {
				partSize = bytes('2MB');
			} else if (partSize > maxPartSize) {
				partSize = maxPartSize;
			}
			const options = {
				// 并发上传的分片个数 最小1 最大10
				parallel: that.parallel <= 0 ? 4 : that.parallel > 10 ? 10 : that.parallel,
				partSize: partSize, // 每个part的大小,单位为b,此处设置为2MB
				timeout: 1000 * 60 * 10, //设置超时时间单位毫秒,此处设置为60秒
				filepath,
				progress,
				// callback: {
				//     url: `/project/attachment/app/uploadFileCenter`,
				//     host: api_pm,
				//     /* eslint no-template-curly-in-string: [0] */
				//     body: 'bucket=${bucket}&object=${object}&etag=${etag}&size=${size}&mimeType=${mimeType}&imageInfo.height=${imageInfo.height}&imageInfo.width=${imageInfo.width}&imageInfo.format=${imageInfo.format}&my_var=${x:my_var}',
				//     contentType: 'application/json',
				//     customValue: {
				//         var1: 'value1',
				//         var2: 'value2',
				//     },
				// },
			};
			if (isRetrySlice) {
				const checkpoint = that.checkpointMap.get(file.uid);
				if (checkpoint) options.checkpoint = checkpoint;
			}
			return options;
		},
		/**
		 * 分段上传
		 * @param file 文件
		 * @param param 上传监听事件 onSuccess | onError | onProgress
		 * @param options 上传配置参数 this.getUploadOptions
		 *
		 **/
		multipartUpload(file, param, options) {
			const client = this.aliYun;
			return new Promise(resolve => {
				client
					.multipartUpload(options.filepath, file, options)
					.then(result => {
						const { res } = result;
						if (res && res.status === 200) {
							const [url] = res.requestUrls;
							const data = {
								url: url.split('?')[0],
								name: file.name,
								response: res,
								raw: file,
								status: 'success',
								suffix: options.suffix,
								filepath: options.filepath,
							};
							param.onSuccess(data, file);
							resolve(data);
							const find = this.images.find(value => value.uid === file.uid);
							if (find) find.status = data.status;
						} else {
							throw new Error(res);
						}
					})
					.catch(err => {
						let status = 'fail';
						let message = '阿里云OSS上传图片失败回调';
						if (err && err.status === 0) {
							message = '取消或暂停';
							status = this.is_cancel_upload ? 'fail' : 'pause';
						}
						console.log(message, err);
						const data = { response: err, raw: file, status, message: '' };
						resolve(data);
						param.onError(data, file);
						const find = this.images.find(value => value.uid === file.uid);
						if (find) find.status = status;
					});
			});
		},
		// 开始上传
		sliceUpload(param) {
			try {
				const { file } = param;
				const filepos = this.upload_pos(file.filename || file.name);
				const options = this.getUploadOptions(param, filepos.filepath);
				return this.multipartUpload(file, param, { ...options, ...filepos });
			} catch (err) {
				console.log(err);
				return Promise.reject(err);
			}
		},
		// 重新上传
		resumeUpload(item) {
			if (!['fail', 'pause'].includes(item.status) || !item.raw) return;
			try {
				const file = item.raw;
				const checkpoint = this.checkpointMap.get(file.uid);
				const filepath = item.filepath;
				const filepos = this.upload_pos(file.filename || file.name);
				item.status = 'uploading';
				const param = {
					file,
					onProgress({ percent, filepath }, file) {
						item.raw = file;
						const percentage = percent;
						item.progress = {
							uploadStarted: true,
							bytesUploaded: getBytesUploaded(file, percentage),
							bytesTotal: file.size,
							uploadComplete: false,
							percentage,
						};
						item.percentage = percentage;
					},
					onError({ status }) {
						item.status = status;
					},
					onSuccess({ url }, file) {
						if (item && item.progress) item.progress.uploadComplete = true;
						item.url = url;
						item.status = 'success';
					},
				};
				const options = this.getUploadOptions(param, filepath, !!checkpoint);
				return this.multipartUpload(file, param, { ...options, ...filepos, filepath });
			} catch (e) {
				console.log(e);
				return Promise.reject(e);
			}
		},
		// 收集上传数据
		handleHttpRequest(param) {
			this.requestQueue.push(param);
		},
		// 文件全部上传完成后监听
		handleFileChangeAll(fileList) {
			let filepath = '',
				list = [];
			const file_list = fileList.filter(file => file && ['success'].includes(file.status));
			const func = () => {
				if (typeof this.close_callback === 'function') {
					this.$nextTick(function() {
						this.close_callback({ list, filepath });
						this.close_callback = null;
					});
				} else if (list.length > 0) {
					this.$emit('change-all', list, filepath);
				}
			};
			if (file_list.length > 0) {
				file_list.forEach(({ raw }) => {
					const find = this.images.find(value => value.uid === raw.uid);
					if (find) find.isSubmit = true;
				});
				// 文件上传全部完成
				filepath = file_list[0].filepath;
				list = cloneDeep(file_list);
				console.log('文件上传全部完成:handleFileChangeAll', list, file_list.length);
			}
			if (fileList.length > 0) {
				func();
				this.is_cancel_upload = false;
			}
		},
		// 处理全部Http请求
		handleHttpRequestAll: debounce(async function(files, is_resume = false) {
			const { isExpiration } = this.auto_upload;
			if (this.isInit === true) return;
			if (!this.aliYun || (isExpiration && isExpiration())) {
				this.isInit = true;
				await this.init();
				this.isInit = false;
			}
			let requestQueue = [];
			const file_list = files && Array.isArray(files) && files.length > 0 ? files : this.images;
			// 处理重新上传(单个)
			// 处理重新上传(多个)
			if (is_resume === true || (files && Array.isArray(files) && files.length > 0)) {
				requestQueue = file_list.filter(file => file && ['fail', 'pause'].includes(file.status)).map(file => this.resumeUpload(file));
			} else {
				requestQueue = this.requestQueue.map(param => this.sliceUpload(param));
			}
			console.log(requestQueue, '重试上传');
			if (requestQueue.length === 0) return;
			this.requestQueue = [];
			const results = await Promise.all(requestQueue);
			if (results.length === requestQueue.length && results.length > 0) {
				this.handleFileChangeAll(results);
			}
		}, 300),
		// 处理重试上传(单)
		handleRetryUpload(id, item) {
			const find = this.images.find(value => value.uid === id);
			if (find) this.allResumeUpload(find);
		},
		// 全部重新上传
		allResumeUpload(file) {
			this.handleHttpRequestAll(file.uid > 0 ? [file] : null, true);
		},
		// 暂停分片上传(所有)
		handleUploadCancel() {
			Array.isArray(this.aliYuns) &&
				this.aliYuns.forEach(client => {
					client && client.cancel();
				});
		},
		addFiles(files) {
			if (!Array.isArray(files)) return;
			const p = files.map(raw => {
				return new Promise(resolve => {
					const filepos = this.upload_pos(raw.filename || raw.name);
					raw.uid = Date.now();
					const file = {
						raw: raw,
						name: raw.name,
						size: raw.size,
						percentage: 0,
						status: 'pause',
						uid: raw.uid,
						url: '',
						filepath: filepos.filepath,
					};
					// window.createObjectURL(raw)
					this.handleBeforeUpload(raw)
						.then(() => {
							this.setFileList(file);
							resolve(file);
						})
						.catch(reason => {
							resolve();
						});
				});
			});
			Promise.all(p).then(files => {
				this.handleHttpRequestAll(files);
			});
		},
		// 取消上传
		handleCancelUpload(bol = true) {
			if (this.uploading_num > 0) {
				this.$ele
					.$confirm(`是否取消正在进行中的任务?`, '取消任务\n', {
						confirmButtonText: '取消任务',
						showCancelButton: false,
						customClass: 'azm-message-box',
						confirmButtonClass: 'bg-orange',
						dangerouslyUseHTMLString: true,
						center: true,
					})
					.then(() => {
						this.clear(null, bol);
					});
			} else {
				this.clear(null, bol);
			}
		},
		// 移除失败或暂停的任务
		handleFailRemove() {
			const image = [...this.images];
			this.clearFiles();
			this.images = image.filter(file => !['fail', 'pause'].includes(file.status));
		},
		/**
		 * 清除
		 *
		 * @param callback
		 * @param bol
		 */
		clear(callback, bol = true) {
			if (typeof this.close_callback === 'function') return;
			this.is_cancel_upload = true;
			this.close_callback = callback;
			if (bol) this.images = [];
			else
				this.images.forEach(file => {
					if (file.status === 'pause') file.status = 'fail';
				});
			this.handleClose(bol === false);
		},
		// 关闭
		close() {
			this.clear();
			this.aliYuns = null;
			this.$refs.upload.clearFiles();
		},
		// 手动上传文件列表
		submit() {
			this.$refs.upload && this.$refs.upload.submit();
		},
		// 取消上传请求
		abort() {
			this.handleUploadCancel();
		},
		// 清除文件
		clearFiles() {
			this.is_cancel_upload = true;
			this.abort();
			this.$refs.upload && this.$refs.upload.clearFiles();
			this.images = [];
			this.$emit('clear');
		},
		removeFile(fileID) {
			const fIndex = this.images.findIndex(file => file.id === fileID);
			if (fIndex > -1) this.images.splice(fIndex, 1);
		},
		// 关闭
		handleClose(visible = false) {
			this.handleUploadCancel();
			this.$emit('update:visible', typeof visible === 'boolean' ? visible : false);
		},
		// 函数触发上传
		btnTrigger() {
			this.$emit('update:visible', true);
			$(this.$refs.upload.$el)
				.find('input')
				.click();
		},
	},
	beforeDestroy() {
		this.close();
	},
};
</script>

<style scoped lang="scss">
.tl-ali-oss-upload {
	::v-deep {
		.el-upload {
			display: block;
		}

		.el-upload-dragger {
			width: 100%;
			border-radius: 0;
			border: 1px dashed transparent;
			height: auto;
			overflow: visible;
		}

		.tl-upload-progress {
			overflow: visible;
		}

		.tl-upload-progress__item {
			border: none;
			border-bottom: 1px solid #f1f1f1;
			border-radius: 0;
		}
	}

	.tl-ali-oss-upload-toolbar {
		height: 28px;
		padding-left: 14px;
		padding-right: 14px;
		background: #f1f2f3;
		border-bottom: 0.5px solid #e5e5e5;
		color: #999;
		font-size: 12px;

		.action-btn {
			cursor: pointer;
			margin: 0 7px;
			color: #a1a2a3;
			text-decoration: none;

			&:hover {
				color: $tl-color-primary;
			}
		}
	}

	.tl-ali-oss-upload-dragger {
		height: 180px;
	}

	.tl-ali-oss__tip {
		background: #fff;
		margin-top: 0;
		padding: 0 14px;
		height: 38px;
		line-height: 38px;
	}
}
</style>
